package xin.alum.aim.client.socks;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.InternalLoggerFactory;
import lombok.SneakyThrows;
import xin.alum.aim.client.websocket.WebSocketClient;
import xin.alum.aim.config.AimConfig;
import xin.alum.aim.model.Aim;
import xin.alum.aim.model.Events;

import java.io.BufferedReader;
import java.io.InputStreamReader;

import static java.lang.System.*;

/**
 * @author Alum(alum @ live.cn)
 * @date 2021/8/20 17:52
 */
public class SocksClient {

    static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketClient.class);

    public static void main(String[] args) throws Exception {
        out.println("数据通信协议选择：");
        out.println("    0-Text");
        out.println("    1-Json");
        out.println("    2-Binary");
        out.println("    3-ProtoBuf");
        out.println("    4-Tlv");
        out.print("请输入数据通信协议(0-4)：");
        int agreement = in.read() - 48;//Read到的是ascii码
        AimConfig AimConfig = new AimConfig();
        Aim.Agreement g = Aim.Agreement.forNumber(agreement);
        AimConfig.setAgreement(g);
        run(AimConfig);
    }

    @SneakyThrows
    public static void run(AimConfig clientProperties) {
        // Configure SSL.
        SslContext sslCtx = null;
        if (clientProperties.isSsl()) {
            sslCtx = SslContextBuilder.forClient().trustManager(InsecureTrustManagerFactory.INSTANCE).build();
        }
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            Bootstrap b = new Bootstrap();
            b.group(group).channel(NioSocketChannel.class).handler(new SocksClientInitializer(sslCtx, clientProperties));
            // Start the connection attempt.
            Channel ch = b.connect(clientProperties.getHost(), clientProperties.getPort()).sync().channel();
            // Read commands from the stdin.
            ChannelFuture lastWriteFuture = null;
            BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
            int agreement = clientProperties.getAgreement().getNumber();
            if (agreement == Aim.Agreement.ProtoBuf_VALUE) {
                //通过Login对接发送握手协议
                Events<Aim.Login> events = new Events<>("Handshake");
                Aim.Login.Builder login = Aim.Login.newBuilder();
                login.setToken("Token" + ch.id().asShortText());
                login.setAgreement(Aim.Agreement.forNumber(agreement));
                events.setData(login.build());
                ch.writeAndFlush(events).addListener(l -> err.println(l.isSuccess()));
            } else {
                //直接发送握手协议数字
                ByteBuf byteBuf = ch.alloc().buffer();
                byteBuf.writeInt(agreement);
                ch.writeAndFlush(byteBuf).addListener(l -> err.println(l.isSuccess()));
            }

            do {
                String line = in.readLine();
                if (line == null) {
                    break;
                }
                lastWriteFuture = write(ch, line, clientProperties);
                lastWriteFuture.addListener((ChannelFutureListener) channelFuture -> err.println("消息发送：" + channelFuture.isSuccess()));
                // If user typed the 'bye' command, wait until the server closes
                // the connection.
                if ("bye".equalsIgnoreCase(line)) {
                    ch.close();
//                   ch.closeFuture().sync();
                    break;
                }
            } while (true);

            // Wait until all messages are flushed before closing the channel.
            if (lastWriteFuture != null) {
                lastWriteFuture.sync();
            }
        } finally {
            // The connection is closed automatically on shutdown.
            group.shutdownGracefully();
        }
    }

    private static ChannelFuture write(Channel ch, String msg, AimConfig clientProperties) {
        if (msg.isEmpty()) {
            msg = "测试";
        }
        //传输对象
        Events<Aim.Data> events = new Events<>();
        events.setKey("key-" + ch.id().asShortText());
        events.setTimestamp(currentTimeMillis());
        Aim.Data.Builder b = Aim.Data.newBuilder();
        b.putAttrs("msg", msg);
        events.setData(b.build());
        return ch.writeAndFlush(events).addListener(l -> logger.warn("发送：{}", l.isSuccess()));
    }
}
